
using System.Collections.Generic;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using System;

namespace GameStateManager
{
    public class ScreenManager : DrawableGameComponent
    {
        List<GameScreen> screens = new List<GameScreen>();
        List<GameScreen> screensToUpdate = new List<GameScreen>();

        ContentManager content;
        SpriteBatch spriteBatch;
        IGraphicsDeviceService graphicsDeviceService;
        Texture2D blankTexture;

        InputState input = new InputState();

        new public Game Game
        {
            get { return base.Game; }
        }

        new public GraphicsDevice GraphicsDevice
        {
            get { return base.GraphicsDevice; }
        }

        public ContentManager ContentManager
        {
            get { return content; }
        }

        public SpriteBatch SpriteBatch
        {
            get { return spriteBatch; }
        }

        public ScreenManager(Game game)
            : base(game)
        {
            content = new ContentManager(game.Services);

            graphicsDeviceService = (IGraphicsDeviceService)game.Services.GetService(typeof(IGraphicsDeviceService));

            if (graphicsDeviceService == null)
                throw new InvalidOperationException("No graphics device service");
        }

        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            if (loadAllContent)
            {
                spriteBatch = new SpriteBatch(GraphicsDevice);
                blankTexture = content.Load<Texture2D>(@"Content\blank");
            }

            foreach (GameScreen screen in screens)
            {
                screen.LoadGraphicsContent(loadAllContent);
            }
        }

        protected override void UnloadGraphicsContent(bool unloadAllContent)
        {
            foreach (GameScreen screen in screens)
                screen.UnLoadGraphicsContent(unloadAllContent);

            content.Unload();
        }

        public void AddScreen(GameScreen screen)
        {
            screen.ScreenManager = this;

            if ((graphicsDeviceService != null) && (graphicsDeviceService.GraphicsDevice != null))
            {
                screen.LoadGraphicsContent(true);
            }

            screens.Add(screen);
        }

        public void RemoveScreen(GameScreen screen)
        {
            if ((graphicsDeviceService != null) && (graphicsDeviceService.GraphicsDevice != null))
            {
                screen.UnLoadGraphicsContent(true);
            }

            screens.Remove(screen);
            screensToUpdate.Remove(screen);
        }

        public override void Update(GameTime gameTime)
        {
            //update the input states
            input.Update();

            screensToUpdate.Clear();

            foreach (GameScreen screen in screens)
                screensToUpdate.Add(screen);

            bool otherScreenHasFocus = false;

            //Update each of the screens
            while (screensToUpdate.Count > 0)
            {
                GameScreen screen = screensToUpdate[screensToUpdate.Count - 1];
                screensToUpdate.RemoveAt(screensToUpdate.Count - 1);

                //Update the screen - always called unlike HandleInput
                screen.Update(gameTime, otherScreenHasFocus);

                if (screen.ScreenState == ScreenState.TransitionOn ||
                    screen.ScreenState == ScreenState.Active)
                {
                    //If this is the first active screen we have come across
                    //the give it the focus
                    if (!otherScreenHasFocus)
                    {
                        screen.HandleInput(input, gameTime);
                        otherScreenHasFocus = true;
                    }
                    
                }
            }
        }

        public override void Draw(GameTime gameTime)
        {
            foreach (GameScreen screen in screens)
            {
                if (screen.ScreenState == ScreenState.Hidden)
                    continue;

                screen.Draw(gameTime);
            }
        }

        public GameScreen[] GetScreens()
        {
            return screens.ToArray();
        }

        /// <summary>
        /// Helper draws a translucent black fullscreen sprite, used for fading
        /// screens in and out, and for darkening the background behind popups.
        /// </summary>
        public void FadeBackBufferToBlack(int alpha)
        {
            Viewport viewport = GraphicsDevice.Viewport;

            spriteBatch.Begin();

            spriteBatch.Draw(blankTexture,
                             new Rectangle(0, 0, viewport.Width, viewport.Height),
                             new Color(0, 0, 0, (byte)alpha));

            spriteBatch.End();
        }

        public Rectangle GetTitleSafeArea()
        {
            Viewport viewport = GraphicsDevice.Viewport;
            float widthOffset, heightOffset;

            widthOffset = (viewport.Width - (viewport.Width * 0.80f)) / 2f;
            heightOffset = (viewport.Height - (viewport.Height * 0.80f)) / 2f;

            Rectangle safeArea = new Rectangle((int)widthOffset, (int)heightOffset, (int)(viewport.Width - widthOffset), (int)(viewport.Height - heightOffset));

            return safeArea;
        }

        public static Rectangle CalculateTitleSafeArea(Viewport viewport)
        {
            float widthOffset, heightOffset;

            widthOffset = (viewport.Width - (viewport.Width * 0.80f)) / 2f;
            heightOffset = (viewport.Height - (viewport.Height * 0.80f)) / 2f;

            Rectangle safeArea = new Rectangle((int)widthOffset, (int)heightOffset, (int)(viewport.Width - widthOffset), (int)(viewport.Height - heightOffset));

            return safeArea;
        }
    }
}
